import axios from 'axios';
import type { RequestOptions, ResponseData, HttpAdapter } from './types';
import config from '@/utils/request/config';
import { checkBodySize } from './utils';
import fetchAdapter from './adapters/fetchAdapter';
import axiosAdapter from './adapters/axiosAdapter';
import xhrAdapter from './adapters/xhrAdapter';
import { createAbortController } from './utils';

class HttpRequest {
  private adapters: { name: string; adapter: HttpAdapter }[];
  private pendingRequests: Map<symbol, AbortController>;

  constructor() {
    this.adapters = this.detectAdapters();
    this.pendingRequests = new Map();
  }

  private detectAdapters() {
    const adapters: { name: string; adapter: HttpAdapter }[] = [];

    // 检测并添加可用的适配器，按优先级排序
    if (typeof fetch === 'function') {
      adapters.push({ name: 'fetch', adapter: fetchAdapter });
    }

    if (typeof axios !== 'undefined') {
      adapters.push({ name: 'axios', adapter: axiosAdapter });
    }

    // 总是添加XHR适配器
    adapters.push({ name: 'xhr', adapter: xhrAdapter });

    return adapters;
  }

  public async request<T>(url: string, options: RequestOptions = {}): Promise<ResponseData<T>> {
    // 检查请求体大小
    checkBodySize(options.body);

    // 合并配置
    const mergedOptions: RequestOptions = {
      ...options,
      headers: {
        ...config.DEFAULT_HEADERS,
        ...options.headers,
      },
      timeout: options.timeout || config.TIMEOUT,
    };

    // 创建AbortController
    const { controller, signal } = createAbortController();
    const requestId = Symbol('requestId');
    this.pendingRequests.set(requestId, controller);

    try {
      // 尝试按优先级使用适配器
      for (const { name, adapter } of this.adapters) {
        try {
          const response = await adapter<T>(url, { ...mergedOptions, signal });
          return response;
        } catch (error) {
          console.warn(`Request failed with ${name}, trying next adapter...`, error);
          // 继续尝试下一个适配器
          continue;
        }
      }

      throw new Error('All adapters failed');
    } finally {
      this.pendingRequests.delete(requestId);
    }
  }

  public cancelRequest(requestId: symbol): void {
    const controller = this.pendingRequests.get(requestId);
    if (controller) {
      controller.abort();
      this.pendingRequests.delete(requestId);
    }
  }

  public cancelAllRequests(): void {
    for (const controller of this.pendingRequests.values()) {
      controller.abort();
    }
    this.pendingRequests.clear();
  }
}

export default new HttpRequest();
